﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Threading;

namespace HSIA
{
    public class ProcessWarningData
    {
        public static DatabaseObject dbo;
        public static string strConnec = "";

        public static void ProcessData(DatabaseObject pdbo, string sReceiverKeyID, string gateherDate, string connec)
        {
            if (dbo == null) dbo = pdbo;

            strConnec = connec;

            string sql = string.Format(@"SELECT a.ReceiverId,a.SensorId,a.DepartmentId,a.ClassId,b.PARA_1,b.PARA_2,b.PARA_3 FROM dbo.Sys_Device a,dbo.Sys_MeasureType b WHERE a.MeasureTypeId=b.KeyId and a.ReceiverId=" + sReceiverKeyID);
            DataTable dt = dbo.GetDataTableBySql(sql, "Device", strConnec);
            if (dt != null && dt.Rows.Count > 0)
            {
                string MId = "PARA_1";
                //处理PARA_1为true的数据
                DataRow[] drPara1 = dt.Select(MId + "=true");
                //循环处理每一个采集器的数据
                foreach (var dr in drPara1)
                {
                    sql = string.Format(@"SELECT ReceiverId,SensorId,GatherNo,GatherDate,{0} FROM dbo.Sys_GatherData WHERE {0} IS NOT NULL AND ReceiverId={1} AND SensorId={2} AND (GatherNo BETWEEN CONVERT(VARCHAR(20),DATEADD(SECOND,-60,'{3}')) AND CONVERT(VARCHAR(20),DATEADD(SECOND,60,'{3}')) or GatherNo='{3}')",
                        MId, PublicMethod.GetInt(dr["ReceiverId"]), PublicMethod.GetInt(dr["SensorId"]), gateherDate);
                    DataTable dtPara1 = dbo.GetDataTableBySql(sql, "GatherData", strConnec);

                    //同一个时间采集器发送的数据可能有多条
                    if (dtPara1 != null && dtPara1.Rows.Count > 0)
                    {
                        for (int i = 0; i < dtPara1.Rows.Count; i++)
                        {
                            //处理报警
                            ProcessParaWarn(dtPara1.Rows[i], 1, MId);
                        }
                    }
                }

                ////处理PARA_2为true的数据
                MId = "PARA_2";
                //处理PARA_1为true的数据
                drPara1 = dt.Select(MId + "=true");
                //循环处理每一个采集器的数据
                foreach (var dr in drPara1)
                {
                    sql = string.Format(@"SELECT ReceiverId,SensorId,GatherNo,GatherDate,{0} FROM dbo.Sys_GatherData WHERE {0} IS NOT NULL AND ReceiverId={1} AND SensorId={2} AND GatherNo='{3}'",
                        MId, PublicMethod.GetInt(dr["ReceiverId"]), PublicMethod.GetInt(dr["SensorId"]), gateherDate);
                    DataTable dtPara1 = dbo.GetDataTableBySql(sql, "GatherData", strConnec);
                    //同一个时间采集器发送的数据可能有多条
                    if (dtPara1 != null && dtPara1.Rows.Count > 0)
                    {
                        for (int i = 0; i < dtPara1.Rows.Count; i++)
                        {
                            //处理报警
                            ProcessParaWarn(dtPara1.Rows[i], 2, MId);
                        }
                    }
                }
            }
        }

        private static void ProcessParaWarn(DataRow dr, int tableidex, string measureid)
        {
            string sql = string.Format(@"SELECT a.ReceiverId,a.SensorId,a.GatherDate,a.{3} as PARA,b.WarnClass,b.WarnType,b.Priority,b.HandleCode,b.UpperValue,b.LowerValue,b.ContinueTime,b.Value,c.Frequency,b.DateBegin1,b.DateEnd1,b.DateBegin2,b.DateEnd2,b.DateBegin3,b.DateEnd3
            FROM dbo.Sys_GatherData a,Sys_Device_Threshold" + tableidex + " b,Sys_Device c WHERE a.ReceiverId=b.ReceiverId AND a.SensorId=b.SensorId AND c.ReceiverId=a.ReceiverId AND c.SensorId=a.SensorId AND a.ReceiverId={0} AND a.SensorId={1} AND a.GatherNo='{2}'", PublicMethod.GetInt(dr["ReceiverId"]), PublicMethod.GetInt(dr["SensorId"]), dr["GatherNo"].ToString(), measureid);
            //对每一条数据进行报警逻辑处理
            DataTable dt = dbo.GetDataTableBySql(sql, "Threshold", strConnec);

            //处理handelCode为ABS报警
            ProcessAbsHandleWarn(dt, measureid);

            //处理handleCode为预警
            ProcessProHandleWarn(dt, measureid);
        }

        #region 报警处理代码
        private static void ProcessAbsHandleWarn(DataTable dt, string measureid)
        {
            string expression = "HandleCode='ABS'";
            string sortOrder = "WarnClass,Priority";
            bool warnFlag = true;//报警标志
            bool isShow = true;//是否显示报警
            DataRow[] drsABS = dt.Select(expression, sortOrder);

            if (drsABS.Length > 0)
            {
                int warnClass = PublicMethod.GetInt(drsABS[0]["WarnClass"]);
                int priority = PublicMethod.GetInt(drsABS[0]["Priority"]);
                for (int i = 0; i < drsABS.Length; i++)
                {
                    int ContinueTime = 0;
                    var sysDeviceInfo = SetSysDeviceInfo(drsABS[i], measureid);
                    //报警类别和优先级与上一条记录一样时，进行处理
                    if (warnClass == sysDeviceInfo.WarnClass && priority == sysDeviceInfo.Priority)
                    {
                        ProcessAbsWarn(ref warnFlag, ref ContinueTime, ref isShow, sysDeviceInfo);
                    }
                    else
                    {
                        if (warnFlag)
                        {
                            int row = i - 1;
                            if (row < 0)
                            {
                                row = 0;
                            }
                            drsABS[i]["ContinueTime"] = ContinueTime;
                            InsertIntoWarnTable(drsABS[row], measureid, isShow);
                            break;
                        }
                        else
                        {
                            ProcessAbsWarn(ref warnFlag, ref ContinueTime, ref isShow, sysDeviceInfo);
                        }
                    }
                    //最后一条记录并且报警标记为True时插入到报警表中
                    if (i == drsABS.Length - 1 && warnFlag)
                    {
                        drsABS[i]["ContinueTime"] = ContinueTime;
                        InsertIntoWarnTable(drsABS[i], measureid, isShow);
                    }
                }
            }
        }

        /// <summary>
        /// 绝对值报警
        /// </summary>
        /// <param name="warnFlag"></param>
        /// <param name="isShow"></param>
        /// <param name="sysDeviceInfo"></param>
        private static void ProcessAbsWarn(ref bool warnFlag, ref int ContinueTime, ref bool isShow, SysDeviceThreshold sysDeviceInfo)
        {
            if (sysDeviceInfo.PARA <= sysDeviceInfo.UpperValue && sysDeviceInfo.PARA >= sysDeviceInfo.LowerValue)
            {
                warnFlag = false;
            }
            else
            {
                string sCondition = "Where ReceiverId=" + sysDeviceInfo.ReceiverId + " and SensorID =" + sysDeviceInfo.SensorId + " and GatherDate>'" + DateTime.Now.AddMinutes(-sysDeviceInfo.Frequency - 2) + "'";
                string sql = "Select count(ReceiverId) Count,max(ContinueTime) ContinueTime from Sys_WarnData ";
                DataTable dt = dbo.GetDataTableBySql(sql + sCondition + " and MeasureId='" + sysDeviceInfo.MeasureId + "'", "Delay", strConnec);
                if (dt == null || dt.Rows.Count == 0 || PublicMethod.GetInt(dt.Rows[0]["Count"]) == 0) ContinueTime = 0;
                else ContinueTime = PublicMethod.GetInt(dt.Rows[0]["ContinueTime"]) + sysDeviceInfo.Frequency;

                isShow = CheckWarnTime(sysDeviceInfo);
            }
        }

        private static void ProcessProHandleWarn(DataTable dt, string measureid)
        {
            //预警处理方法变更
            string absExpression = "HandleCode='ABS'";

            string expression = "HandleCode='PRO'";
            string sortOrder = "WarnClass,Priority";
            bool warnFlag = true;//报警标志
            bool isShow = true;//是否显示报警
            DataRow[] drsPRO = dt.Select(expression, sortOrder);

            //增加报警信息
            DataRow[] drsABS = dt.Select(absExpression, sortOrder);
            if (drsABS.Length > 0 && drsPRO.Length > 0)
            {
                int warnClass = PublicMethod.GetInt(drsPRO[0]["WarnClass"]);
                int priority = PublicMethod.GetInt(drsPRO[0]["Priority"]);
                for (int i = 0; i < drsPRO.Length; i++)
                {
                    int ContinueTime = 0;
                    var sysDeviceInfo = SetSysDeviceInfo(drsPRO[i], measureid);

                    var sysDeviceInfoByAbs = SetSysDeviceInfo(drsABS[i], measureid);
                    //报警类别和优先级与上一条记录一样时，进行处理
                    if (warnClass == sysDeviceInfo.WarnClass && priority == sysDeviceInfo.Priority)
                    {
                        ProcessProWarn(ref warnFlag, ref ContinueTime, ref isShow, sysDeviceInfo, sysDeviceInfoByAbs);
                    }
                    else
                    {
                        if (warnFlag)
                        {
                            int row = i - 1;
                            if (row < 0)
                            {
                                row = 0;
                            }
                            InsertIntoWarnTable(drsPRO[row], measureid, isShow);
                            break;
                        }
                        else
                        {
                            ProcessProWarn(ref warnFlag, ref ContinueTime, ref isShow, sysDeviceInfo, sysDeviceInfoByAbs);
                        }
                    }
                    //最后一条记录并且报警标记为True时插入到报警表中
                    if (i == drsPRO.Length - 1 && warnFlag)
                    {
                        InsertIntoWarnTable(drsPRO[i], measureid, isShow);
                    }
                }
            }
            else if (drsPRO.Length > 0)
            {
                int warnClass = PublicMethod.GetInt(drsPRO[0]["WarnClass"]);
                int priority = PublicMethod.GetInt(drsPRO[0]["Priority"]);
                for (int i = 0; i < drsPRO.Length; i++)
                {
                    var sysDeviceInfo = SetSysDeviceInfo(drsPRO[i], measureid);
                    //报警类别和优先级与上一条记录一样时，进行处理
                    if (warnClass == sysDeviceInfo.WarnClass && priority == sysDeviceInfo.Priority)
                    {
                        ProcessProWarn(ref warnFlag, ref isShow, sysDeviceInfo);
                    }
                    else
                    {
                        if (warnFlag)
                        {
                            int row = i - 1;
                            if (row < 0)
                            {
                                row = 0;
                            }
                            InsertIntoWarnTable(drsPRO[row], measureid, isShow);
                            break;
                        }
                        else
                        {
                            ProcessProWarn(ref warnFlag, ref isShow, sysDeviceInfo);
                        }
                    }
                    //最后一条记录并且报警标记为True时插入到报警表中
                    if (i == drsPRO.Length - 1 && warnFlag)
                    {
                        InsertIntoWarnTable(drsPRO[i], measureid, isShow);
                    }
                }
            }
        }

        /// <summary>
        /// 预报警方法2，如果采集数据位于报警与预警数值之间，则预警
        /// </summary>
        /// <param name="warnFlag"></param>
        /// <param name="isShow"></param>
        /// <param name="sysDeviceInfo"></param>
        /// <param name="sysDeviceInfoByAbs"></param>
        private static void ProcessProWarn(ref bool warnFlag, ref int ContinueTime, ref bool isShow, SysDeviceThreshold sysDeviceInfo, SysDeviceThreshold sysDeviceInfoByAbs)
        {
            warnFlag = false;

            if ((sysDeviceInfo.PARA > sysDeviceInfoByAbs.LowerValue && sysDeviceInfo.PARA < sysDeviceInfo.LowerValue) || (sysDeviceInfo.PARA < sysDeviceInfoByAbs.UpperValue && sysDeviceInfo.PARA > sysDeviceInfo.UpperValue))
            {
                warnFlag = true;
                string sCondition = "Where ReceiverId=" + sysDeviceInfo.ReceiverId + " and SensorID =" + sysDeviceInfo.SensorId + " and GatherDate>'" + DateTime.Now.AddMinutes(-sysDeviceInfo.Frequency - 2) + "'";
                string sql = "Select count(ReceiverId) Count,max(ContinueTime) ContinueTime from Sys_WarnData ";
                DataTable dt = dbo.GetDataTableBySql(sql + sCondition + " and MeasureId='" + sysDeviceInfo.MeasureId + "'", "Delay", strConnec);
                if (dt == null || dt.Rows.Count == 0 || PublicMethod.GetInt(dt.Rows[0]["Count"]) == 0) ContinueTime = 0;
                else ContinueTime = PublicMethod.GetInt(dt.Rows[0]["ContinueTime"]) + sysDeviceInfo.Frequency;

                isShow = CheckWarnTime(sysDeviceInfo);
            }
        }

        /// <summary>
        /// 预报警
        /// </summary>
        /// <param name="warnFlag"></param>
        /// <param name="isShow"></param>
        /// <param name="sysDeviceInfo"></param>
        private static void ProcessProWarn(ref bool warnFlag, ref bool isShow, SysDeviceThreshold sysDeviceInfo)
        {
            warnFlag = false;

            if (sysDeviceInfo.PARA <= sysDeviceInfo.UpperValue && sysDeviceInfo.PARA >= sysDeviceInfo.LowerValue)
            {
                string sCondition = "Where ReceiverId=" + sysDeviceInfo.ReceiverId + " and SensorID =" + sysDeviceInfo.SensorId + " and GatherDate>'" + DateTime.Now.AddMinutes(-sysDeviceInfo.ContinueTime) + "'";
                string sql = "Select count(ReceiverId) from Sys_WarnData ";
                DataTable dt = dbo.GetDataTableBySql(sql + sCondition + " and MeasureId='" + sysDeviceInfo.MeasureId + "'", "Delay", strConnec);
                if (dt == null || dt.Rows.Count == 0 || PublicMethod.GetInt(dt.Rows[0][0]) > 0) return;

                sql = "Select count(ReceiverId) from Sys_GatherData {1}";
                dt = dbo.GetDataTableBySql(string.Format(sql, sysDeviceInfo.MeasureId,
                    sCondition + " and (" + sysDeviceInfo.MeasureId + "<" + sysDeviceInfo.LowerValue + " or " +
                    sysDeviceInfo.MeasureId + ">" + sysDeviceInfo.UpperValue + " ) "), "Delay", strConnec);
                if (dt != null && PublicMethod.GetInt(dt.Rows[0][0]) > 0) return;

                sql = "Select max({0}) max,min({0}) min from Sys_GatherData {1}";
                dt = dbo.GetDataTableBySql(string.Format(sql, sysDeviceInfo.MeasureId, sCondition), "Delay", strConnec);
                if (dt != null && PublicMethod.GetDecimal(dt.Rows[0]["max"]) - PublicMethod.GetDecimal(dt.Rows[0]["min"]) > sysDeviceInfo.Value)
                {
                    warnFlag = true;
                    isShow = CheckWarnTime(sysDeviceInfo);
                }
            }

        }

        private static bool CheckWarnTime(SysDeviceThreshold sysDeviceInfo)
        {
            bool b = CompareTime(sysDeviceInfo.GatherTime, sysDeviceInfo.DateBegin1, sysDeviceInfo.DateEnd1) ||
                     CompareTime(sysDeviceInfo.GatherTime, sysDeviceInfo.DateBegin2, sysDeviceInfo.DateEnd2) ||
                     CompareTime(sysDeviceInfo.GatherTime, sysDeviceInfo.DateBegin3, sysDeviceInfo.DateEnd3);
            return !b;
        }

        private static bool CompareTime(string stime, string stime_begin, string stime_end)
        {
            bool b = false;
            DateTime time, time_begin, time_end;
            if (DateTime.TryParse(stime, out time) && DateTime.TryParse(stime_begin, out time_begin) && DateTime.TryParse(stime_end, out time_end))
            {
                TimeSpan tstime = new TimeSpan(time.Hour, time.Minute, time.Second);
                TimeSpan tsbegin = new TimeSpan(time_begin.Hour, time_begin.Minute, time_begin.Second);
                TimeSpan tsend = new TimeSpan(time_end.Hour, time_end.Minute, time_end.Second);

                b = tstime > tsbegin && tstime < tsend;
            }
            return b;
        }
        #endregion

        private static void InsertIntoWarnTable(DataRow dr, string measureid, bool isShow)
        {
            string sql = string.Format(@"INSERT INTO Sys_WarnData (ReceiverId,SensorId,GatherDate,Priority,WarnType,HandleCode,MeasureId,MeasureValue,UpperValue,LowerValue,ContinueTime,isShow)VALUES({0},{1},'{2}',{3},'{4}','{5}','{6}','{7}',{8},{9},{10},'{11}');",
                PublicMethod.GetInt(dr["ReceiverId"]), PublicMethod.GetInt(dr["SensorId"]), dr["GatherDate"], PublicMethod.GetInt(dr["Priority"]), dr["WarnType"], dr["HandleCode"], measureid, PublicMethod.GetDecimal(dr["PARA"]),
                PublicMethod.GetDecimal(dr["UpperValue"]), PublicMethod.GetDecimal(dr["LowerValue"]), PublicMethod.GetInt(dr["ContinueTime"]), isShow);
            string statue = string.Empty;
            string wartype = string.Empty;
            if (isShow)
            {
                switch (measureid)
                {
                    case "PARA_1":
                        switch (dr["HandleCode"].ToString())
                        {
                            case "abs": statue = "A0"; wartype = "[温度]报警[" + dr["PARA"] + "℃]"; break;
                            case "pro": statue = "P0"; wartype = "[温度]预警[" + dr["PARA"] + "℃]"; break;
                            default: statue = ""; break;
                        };
                        //wartype = "[温度]报警[" + dr["PARA"] + "℃]";
                        break;
                    case "PARA_2":
                        switch (dr["HandleCode"].ToString())
                        {
                            case "abs": statue = "A1"; wartype = "[湿度]报警[" + dr["PARA"] + "%]"; break;
                            case "pro": statue = "P1"; wartype = "[湿度]预警[" + dr["PARA"] + "%]"; break;
                            default: statue = ""; break;
                        };
                        //wartype = "[湿度]报警[" + dr["PARA"] + "%]";
                        break;
                    default: break;
                }
            }
            else
            {
                statue = "D1";
            }
            int receiverid = PublicMethod.GetInt(dr["ReceiverId"]);
            int sensorid = PublicMethod.GetInt(dr["SensorId"]);
            if (statue != "")
            {
                sql += string.Format("UPDATE Sys_Map SET WarnMeasure='{2}',WarnType='{3}',State='{4}',SentStatus='{5}' WHERE ReceiverId={0} AND SensorId={1}",
                receiverid, sensorid, measureid, dr["WarnType"], statue, 0);
            }

            statue = dbo.ExcuteSQL(sql, strConnec);
            //if (statue == "OK")
            //{
            //    string[] info = MyReceiver.GetDeviceInfo(dbo, receiverid, sensorid, strConnec);
            //    string msg = string.Format("{0}：{1}，请即时处理！【国药物流】", info[1].TrimEnd('-'), wartype);
            //    MySms.AddSms(dbo, info, msg, strConnec);
            //}

        }

        private static SysDeviceThreshold SetSysDeviceInfo(DataRow dr, string measureid)
        {
            SysDeviceThreshold deviceInfo = new SysDeviceThreshold();

            deviceInfo.MeasureId = measureid;
            deviceInfo.ReceiverId = PublicMethod.GetInt(dr["ReceiverId"]);
            deviceInfo.SensorId = PublicMethod.GetInt(dr["SensorId"]);

            deviceInfo.WarnClass = PublicMethod.GetInt(dr["WarnClass"]);
            deviceInfo.WarnType = PublicMethod.GetInt(dr["WarnType"]);
            deviceInfo.Priority = PublicMethod.GetInt(dr["Priority"]);
            deviceInfo.HandleCode = PublicMethod.GetString(dr["HandleCode"]);
            deviceInfo.UpperValue = PublicMethod.GetDecimal(dr["UpperValue"]);
            deviceInfo.LowerValue = PublicMethod.GetDecimal(dr["LowerValue"]);
            deviceInfo.PARA = PublicMethod.GetDecimal(dr["PARA"]);
            deviceInfo.ContinueTime = PublicMethod.GetInt(dr["ContinueTime"]);
            deviceInfo.Value = PublicMethod.GetInt(dr["Value"]);
            deviceInfo.Frequency = PublicMethod.GetInt(dr["Frequency"]);

            deviceInfo.DateBegin1 = PublicMethod.GetString(dr["DateBegin1"]);
            deviceInfo.DateEnd1 = PublicMethod.GetString(dr["DateEnd1"]);
            deviceInfo.DateBegin2 = PublicMethod.GetString(dr["DateBegin2"]);
            deviceInfo.DateEnd2 = PublicMethod.GetString(dr["DateEnd2"]);
            deviceInfo.DateBegin3 = PublicMethod.GetString(dr["DateBegin3"]);
            deviceInfo.DateEnd3 = PublicMethod.GetString(dr["DateEnd3"]);
            deviceInfo.GatherTime = PublicMethod.GetString(dr["GatherDate"]);

            return deviceInfo;
        }

    }

    public class SysDeviceThreshold
    {
        public int ReceiverId { get; set; }

        public int SensorId { get; set; }

        public int WarnClass { get; set; }

        public int WarnType { get; set; }

        public int Priority { get; set; }

        public string HandleCode { get; set; }

        public decimal UpperValue { get; set; }

        public decimal LowerValue { get; set; }

        public string MeasureId { get; set; }

        public decimal PARA { get; set; }

        public int ContinueTime { get; set; }

        public int Value { get; set; }

        public int Frequency { get; set; }

        public string DateBegin1 { get; set; }

        public string DateEnd1 { get; set; }

        public string DateBegin2 { get; set; }

        public string DateEnd2 { get; set; }

        public string DateBegin3 { get; set; }

        public string DateEnd3 { get; set; }

        public string GatherTime { get; set; }

    }

}

